﻿using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Text;
using CrystalDecisions.Enterprise;
using CrystalDecisions.Enterprise.Dest;

namespace BO.Management.PowerShell
{

    [Cmdlet(VerbsCommon.Set, "Notification", DefaultParameterSetName = CONNECT_SECWINAD)]
    public class SetNotification : BaseActionObject<ContentGenericProvider, InfoObject>
    {
        public override ContentGenericProvider GetProvider()
        {
            return new ContentGenericProvider(this.LogonProvider);
        }

        [Parameter(Position = 7, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = true)]
        [Parameter(Position = 5, ParameterSetName = CONNECT_SECWINAD, Mandatory = true)]
        public Notification NotificationType { get; set; }

        [Parameter(Position = 8, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = false)]
        [Parameter(Position = 6, ParameterSetName = CONNECT_SECWINAD, Mandatory = false)]
        public String ConfigurationFilePath { get; set; }

        [Parameter(Position = 9, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = false)]
        [Parameter(Position = 7, ParameterSetName = CONNECT_SECWINAD, Mandatory = false)]
        public String DomainName { get; set; }

        [Parameter(Position = 10, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = false)]
        [Parameter(Position = 8, ParameterSetName = CONNECT_SECWINAD, Mandatory = false)]
        public String SmtpServer { get; set; }

        [Parameter(Position = 11, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = false)]
        [Parameter(Position = 9, ParameterSetName = CONNECT_SECWINAD, Mandatory = false)]
        public Int32? SmtpServerPort { get; set; }

        [Parameter(Position = 12, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = false)]
        [Parameter(Position = 10, ParameterSetName = CONNECT_SECWINAD, Mandatory = false)]
        public CeAuthentication SmtpAuthentication { get; set; }

        [Parameter(Position = 13, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = false)]
        [Parameter(Position = 11, ParameterSetName = CONNECT_SECWINAD, Mandatory = false)]
        public String SmtpUserName { get; set; }

        [Parameter(Position = 14, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = false)]
        [Parameter(Position = 12, ParameterSetName = CONNECT_SECWINAD, Mandatory = false)]
        public String SmtpPassword { get; set; }

        [Parameter(Position = 15, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = false)]
        [Parameter(Position = 13, ParameterSetName = CONNECT_SECWINAD, Mandatory = false)]
        public String[] To { get; set; }

        [Parameter(Position = 16, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = false)]
        [Parameter(Position = 14, ParameterSetName = CONNECT_SECWINAD, Mandatory = false)]
        public String[] Cc { get; set; }

        [Parameter(Position = 17, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = false)]
        [Parameter(Position = 15, ParameterSetName = CONNECT_SECWINAD, Mandatory = false)]
        public String From { get; set; }

        [Parameter(Position = 18, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = false)]
        [Parameter(Position = 16, ParameterSetName = CONNECT_SECWINAD, Mandatory = false)]
        public String Subject { get; set; }

        [Parameter(Position = 19, ParameterSetName = CONNECT_SECENTERPRISE, Mandatory = false)]
        [Parameter(Position = 17, ParameterSetName = CONNECT_SECWINAD, Mandatory = false)]
        public String Message { get; set; }


        private NotificationConfiguration SmtpConfiguration;

        /// <summary>
        /// Check if all parameters are correct to create a notification
        /// </summary>
        /// <param name="notifConfiguration"></param>
        /// <returns></returns>
        private Boolean IsConfigurationCorrect(NotificationConfiguration notifConfiguration)
        {
            Boolean result = true;
            //Check the domain Name
            if (String.IsNullOrEmpty(notifConfiguration.DomainName))
            {
                this.WriteError(BOErrorManagement.GetErrorRecord(BOErrorCode.InvalidArgument, "Null argument",
                    new PSArgumentNullException("DomainName")));
                return false;
            }

            //Check the message
            if (String.IsNullOrEmpty(notifConfiguration.Message))
            {
                this.WriteError(BOErrorManagement.GetErrorRecord(BOErrorCode.InvalidArgument, "Null argument",
                    new PSArgumentNullException("Message")));
                return false;
            }

            //Check the SenderAddress
            if (String.IsNullOrEmpty(notifConfiguration.SenderAddress))
            {
                this.WriteError(BOErrorManagement.GetErrorRecord(BOErrorCode.InvalidArgument, "Null argument",
                    new PSArgumentNullException("SenderAddress")));
                return false;
            }

            //Check the SenderAddress
            if (String.IsNullOrEmpty(notifConfiguration.ServerName))
            {
                this.WriteError(BOErrorManagement.GetErrorRecord(BOErrorCode.InvalidArgument, "Null argument",
                    new PSArgumentNullException("ServerName")));
                return false;
            }

            //Check the Authentication configuration
            if (notifConfiguration.SMTPAuthentication != CeAuthentication.ceAuthNone)
            {
                if (String.IsNullOrEmpty(notifConfiguration.SMTPUserName))
                {
                    this.WriteError(BOErrorManagement.GetErrorRecord(BOErrorCode.InvalidArgument, "User Name is mandatory when smtp authentication is configured to Login or Plain Text",
                        new PSArgumentNullException("UserName")));
                    return false;
                }
            }

            //Check the Subject
            if (String.IsNullOrEmpty(notifConfiguration.Subject))
            {
                this.WriteError(BOErrorManagement.GetErrorRecord(BOErrorCode.InvalidArgument, "Null argument",
                    new PSArgumentNullException("Subject")));
                return false;
            }

            //Check the ToAdress
            if (notifConfiguration.ToAddresses == null || notifConfiguration.ToAddresses.Length == 0)
            {
                this.WriteError(BOErrorManagement.GetErrorRecord(BOErrorCode.InvalidArgument, "Null argument",
                    new PSArgumentNullException("To")));
                return false;
            }

            return result;
        }

        /// <summary>
        /// Get configuration for notification according the parameters
        /// </summary>
        /// <returns></returns>
        private NotificationConfiguration GetNotificationConfiguration()
        {
            NotificationConfiguration notifConfiguration;

            if (!String.IsNullOrEmpty(this.ConfigurationFilePath))
            {
                WriteVerbose("Get Notification Configuration from configuration file");

                //Load the notification configuration from Configuration File
                if (!System.IO.File.Exists(this.ConfigurationFilePath))
                {
                    this.ThrowTerminatingErrorWithExitCode(BOErrorCode.InvalidArgument,
                        String.Format("the configuration file {0} doesn't exist", this.ConfigurationFilePath));
                }

                System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(NotificationConfiguration));
                using (System.IO.FileStream s = new System.IO.FileStream(this.ConfigurationFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read))
                {
                    notifConfiguration = (NotificationConfiguration)x.Deserialize(s);
                }

            }
            else
            {
                WriteVerbose("Get Notification Configuration from parameters");

                //Load the notification configuration from parameters
                notifConfiguration = new NotificationConfiguration()
                {
                    DomainName = this.DomainName,
                    Message = this.Message,
                    Port = this.SmtpServerPort.HasValue ? this.SmtpServerPort.Value : 25,
                    SenderAddress = this.From,
                    ServerName = this.SmtpServer,
                    SMTPAuthentication = this.SmtpAuthentication,
                    SMTPPassword = this.SmtpPassword,
                    SMTPUserName = this.SmtpUserName,
                    Subject = this.Subject,
                    ToAddresses = this.To,
                    CcAddresses = this.Cc
                };
            }

            if (!this.IsConfigurationCorrect(notifConfiguration))
            {
                WriteVerbose("Notification Configuration is not ok");
                return null;
            }
            else
            {
                WriteVerbose("Notification Configuration is ok");
                return notifConfiguration;
            }
        }


        /// <summary>
        /// Browse the string argument to replace all BO properties between %.
        /// We add a specific property BO_FULLPATH to retrieve the object full path
        /// </summary>
        /// <param name="boeObject"></param>
        /// <param name="value"></param>
        private String ChangeDynamicParameters(InfoObject boeObject, String value)
        {

            this.WriteVerbose(String.Format("ChangeDynamicParameters into {0}", value));

            StringBuilder sb = new StringBuilder(value);

            String patternToFind = "%.*?%(.|$)";

            System.Text.RegularExpressions.MatchCollection results = System.Text.RegularExpressions.Regex.Matches(value, patternToFind, System.Text.RegularExpressions.RegexOptions.Singleline);
            foreach (System.Text.RegularExpressions.Match result in results)
            {
                String boPropertyName = result.Value.Replace("%", String.Empty).Trim();

                foreach (Property property in boeObject.Properties)
                {
                    if (String.Compare(property.Name, boPropertyName, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        sb.Replace(result.Value, property.Value == null ? "null " : property.Value.ToString() + " ");
                    }
                    else if (String.Compare("BO_FULLPATH", boPropertyName, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        sb.Replace(result.Value, BoeProvider.GetFullPath(boeObject).FullPath + " ");
                    }

                }
            }
            this.WriteVerbose(String.Format("New value is {0}", sb.ToString()));
            return sb.ToString();
        }


        protected override void BeginProcessing()
        {
            base.BeginProcessing();
            this.SmtpConfiguration = this.GetNotificationConfiguration();
            if (this.SmtpConfiguration == null)
            {
                WriteVerbose("Notification Configuration is not ok, stop processing....");
                this.ThrowTerminatingErrorWithExitCode(BOErrorCode.NotificationConfigurationError, "Notification Configuration isn't correct");
            }
        }

        public override void WorkWithSingleObject(InfoObject boeObject)
        {
            if (this.SmtpConfiguration == null)
            {
                this.ThrowTerminatingErrorWithExitCode(BOErrorCode.NotificationConfigurationError, "Notification Configuration isn't correct");
                return;
            }

            //Select destations according notification type
            Destinations destinations;

            if (this.NotificationType == Notification.Failure)
            {
                WriteVerbose("Notification Target is notification on Failure");
                destinations = boeObject.SchedulingInfo.Notifications.DestinationsOnFailure;
            }
            else
            {
                WriteVerbose("Notification Target is notification on success");
                destinations = boeObject.SchedulingInfo.Notifications.DestinationsOnSuccess;
            }


            if (destinations != null)
            {

                Destination notification;
                if (destinations.Count == 0)
                {
                    WriteVerbose("No notification exist, create a new notification");
                    notification = destinations.Add(String.Format("Notification {0} on {1}", this.NotificationType, boeObject.Title));
                }
                else
                {
                    WriteVerbose(String.Format("{0} notification exist", destinations[1].Name));
                    notification = destinations[1];
                    notification.Name = String.Format("Notification Echec {0} on {1}", this.NotificationType, boeObject.Title);
                }

                //Load the destination plugin
                WriteVerbose("Load the Smtp Provider to retrieve configuration for destination plugin");
                SmtpProvider provider = new SmtpProvider(this.LogonProvider);
                DestinationPlugin destPlugin = provider.GetDestinationPlugin();

                //Create smtp options
                WriteVerbose("Create the Smtp Options to configure with the configuration data");
                SmtpOptions options = new SmtpOptions(destPlugin.ScheduleOptions);

                String notifcationMsg = this.ChangeDynamicParameters(boeObject, this.SmtpConfiguration.Message);
                WriteVerbose(String.Format("Set Message with {0}", notifcationMsg));
                options.Message = notifcationMsg;

                String notifcationSubject = this.ChangeDynamicParameters(boeObject, this.SmtpConfiguration.Subject);
                WriteVerbose(String.Format("Set Subject with {0}", notifcationSubject));
                options.Subject = notifcationSubject;

                WriteVerbose(String.Format("Set DomaiName with {0}", this.SmtpConfiguration.DomainName));
                options.DomainName = this.SmtpConfiguration.DomainName;
                WriteVerbose(String.Format("Set ServerName with {0}", this.SmtpConfiguration.ServerName));
                options.ServerName = this.SmtpConfiguration.ServerName;
                WriteVerbose(String.Format("Set Port with {0}", this.SmtpConfiguration.Port));
                options.Port = this.SmtpConfiguration.Port;
                WriteVerbose(String.Format("Set SMTPAuthentication with {0}", this.SmtpConfiguration.SMTPAuthentication));
                options.SMTPAuthentication = this.SmtpConfiguration.SMTPAuthentication;

                if (options.SMTPAuthentication != CeAuthentication.ceAuthNone)
                {
                    WriteVerbose(String.Format("Set SMTPPassword with {0}", "*****************"));
                    options.SMTPPassword = this.SmtpConfiguration.SMTPPassword;
                    WriteVerbose(String.Format("Set SMTPUserName with {0}", this.SmtpConfiguration.SMTPUserName));
                    options.SMTPUserName = this.SmtpConfiguration.SMTPUserName;
                }

                WriteVerbose(String.Format("Set SenderAddress with {0}", this.SmtpConfiguration.SenderAddress));
                options.SenderAddress = this.SmtpConfiguration.SenderAddress;

                foreach (String address in this.SmtpConfiguration.ToAddresses)
                {
                    WriteVerbose(String.Format("Add this address to {0}", address));
                    options.ToAddresses.Add(address);
                }

                if (this.SmtpConfiguration.CcAddresses != null)
                {
                    foreach (String address in this.SmtpConfiguration.CcAddresses)
                    {
                        WriteVerbose(String.Format("Add this address Cc {0}", address));
                        options.CCAddresses.Add(address);
                    }
                }



                WriteVerbose("Save the instance with notification");
                notification.SetFromPlugin(destPlugin);
                BoeProvider.Commit(boeObject);


                //StringBuilder sb = new StringBuilder();
                //sb.AppendLine("Failed : %SI_PATH% - %SI_NAME%");
                //sb.AppendLine("Owner : %SI_OWNER%");

                //NotificationConfiguration n = new NotificationConfiguration()
                //{
                //    DomainName = "yahoo.fr",
                //    Message = sb.ToString(),
                //    Port = 25,
                //    SenderAddress = "Yannickgobert@yahoo.fr",
                //    ServerName = "mail.smtp.yahoo.fr",
                //    SMTPAuthentication = CeAuthentication.ceAuthLogin,
                //    SMTPPassword = "nana2704",
                //    SMTPUserName = "YannickGobert",
                //    Subject = "Failure on " + boeObject.Title,
                //    ToAddresses = new String[] { "YannickGobert@yahoo.fr", "stef@tes.fr" }
                //};


                //System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(NotificationConfiguration));
                //using (System.IO.FileStream s = new System.IO.FileStream(@"c:\Test2.xml", System.IO.FileMode.CreateNew, System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite))
                //{
                //    x.Serialize(s, n);
                //}
            }
            else
            {
                WriteVerbose("Destinations collection doesn't exist");
            }

            this.WriteObject(destinations);
        }

        public override void WorkWithListObjects(List<InfoObject> boeObjects)
        {
            if (this.SmtpConfiguration == null)
            {
                this.ThrowTerminatingErrorWithExitCode(BOErrorCode.NotificationConfigurationError, "Notification Configuration isn't correct");
                return;
            }

            base.WorkWithListObjects(boeObjects);
        }
    }
}
